/*******************************************************************************
 * @file fntable_export.h
 * @brief 导出函数表的库
 * @note 该库适用于MDK，如果使用gcc则需要修改ld文件
 *******************************************************************************
*/

#ifndef __FNTABLE_EXPORT_H__
#define __FNTABLE_EXPORT_H__

/**
 * @defgroup 自动初始化机制定义
 * @{
 */

#ifndef USED
#define USED __attribute__((used))
#endif // !USED

#ifndef SECTION
#define SECTION(x) __attribute__((section(x)))
#endif //!SECTION

typedef void (*fn_t)(void);

/* 输入段开始 */
#define SECTION_START(section) __##section##_start
/* 输入段结束 */
#define SECTION_END(section) __##section##_end

#if defined(DEBUG)
typedef struct
{
    const char *name;
    fn_t fn_addr;
}fn_desc;

/* 定义输入段开始地址 */
#define SECTION_START_DEF(section) \
        USED const fn_desc SECTION_START(section) SECTION("."#section".0") = {0}
/* 定义输入段结束地址 */
#define SECTION_END_DEF(section) \
        USED const fn_desc SECTION_END(section) SECTION("."#section".1.end") = {0}
/* 导出到BSP自动初始化输入段 */
#define SECTION_EXPORT(section, fn) \
        USED const char __##section##_##fn##_name[] = #fn;  \
        USED const fn_desc __##section##_##fn SECTION("."#section".1") = { \
            .fn_addr = fn,\
            .name = __##section##_##fn##_name\
        }
#else
    /* 定义输入段开始地址 */
#define SECTION_START_DEF(section) \
        USED const fn_t SECTION_START(section) SECTION("."#section".0") = 0
    /* 定义输入段结束地址 */
#define SECTION_END_DEF(section) \
        USED const fn_t SECTION_END(section) SECTION("."#section".1.end") = 0
    /* 导出到BSP自动初始化输入段 */
#define SECTION_EXPORT(section, fn) \
        USED const fn_t __##section##_##fn SECTION("."#section".1") = fn

#endif

/**
 * @} 自动初始化机制定义
 */

#define PRINT printf

/**
 * @brief 遍历函数表
 * @param starte 起始地址
 * @param end 结束地址
 */
void Fntable_Traverse(const void *start, const void *end);

#endif // __FNTABLE_EXPORT_H__
